package com.lwl.blue.seven.test7;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.lwl.blue.seven.dao.Contract7Dao;
import com.lwl.blue.seven.dto.*;
import com.lwl.blue.seven.service.Contract7Service;
import com.lwl.blue.seven.service.ContractItem7Service;
import org.junit.jupiter.api.Test;
import org.junit.jupiter.api.extension.ExtendWith;
import org.mockito.Mock;
import org.mockito.junit.jupiter.MockitoExtension;
import org.springframework.boot.test.context.SpringBootTest;
import org.springframework.transaction.annotation.Transactional;

import javax.validation.ConstraintViolation;
import javax.validation.Validation;
import javax.validation.Validator;
import javax.validation.ValidatorFactory;
import java.math.BigDecimal;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.Date;
import java.util.Set;

import static java.util.Date.*;
import static org.junit.jupiter.api.Assertions.*;

/**
 * 合同相关DTO测试类
 * 用于测试Contract7模块中各个DTO类的属性、验证规则和序列化功能
 */
//@SpringBootTest
//@Transactional
@ExtendWith(MockitoExtension.class)
public class Contract7DTOTest {

    // 验证器工厂，用于创建验证器实例
    private final ValidatorFactory factory = Validation.buildDefaultValidatorFactory();
    // 验证器，用于验证DTO对象的约束条件
    private final Validator validator = factory.getValidator();
    // JSON对象映射器，用于测试DTO的序列化和反序列化
    private final ObjectMapper objectMapper = new ObjectMapper();

    /**
     * 测试Contract7CreateDTO的基本属性设置和获取
     * 验证DTO的getter和setter方法是否正常工作
     */
    @Test
    public void testContract7CreateDTO() {
        Contract7CreateDTO dto = new Contract7CreateDTO();
        dto.setContractNumber("HT2025001");
        dto.setContractName("测试合同");
        dto.setSupplierId(1);
        dto.setTransactionType("采购");

        assertNotNull(dto.getContractNumber());
        assertNotNull(dto.getContractName());
        assertNotNull(dto.getSupplierId());
        assertNotNull(dto.getTransactionType());
        assertEquals("HT2025001", dto.getContractNumber());
        assertEquals("测试合同", dto.getContractName());
        assertEquals(Integer.valueOf(1), dto.getSupplierId());
        assertEquals("采购", dto.getTransactionType());
    }

    /**
     * 测试Contract7CreateDTO的数据验证功能
     * 验证DTO上的JSR-303注解约束是否正常工作
     */
    @Test
    public void testContract7CreateDTOValidation() {
        Contract7CreateDTO dto = new Contract7CreateDTO();

        // 验证空对象，应该存在违反约束的情况
        Set<ConstraintViolation<Contract7CreateDTO>> violations = validator.validate(dto);
        assertFalse(violations.isEmpty());

        // 测试必填字段验证 - 合同编号不能为空
        boolean hasContractNumberError = violations.stream()
                .anyMatch(v -> "contractNumber".equals(v.getPropertyPath().toString()) &&
                              "合同编号不能为空".equals(v.getMessage()));
        assertTrue(hasContractNumberError);

        // 测试必填字段验证 - 合同名称不能为空
        boolean hasContractNameError = violations.stream()
                .anyMatch(v -> "contractName".equals(v.getPropertyPath().toString()) &&
                              "合同名称不能为空".equals(v.getMessage()));
        assertTrue(hasContractNameError);

        // 测试必填字段验证 - 供应商不能为空
        boolean hasSupplierIdError = violations.stream()
                .anyMatch(v -> "supplierId".equals(v.getPropertyPath().toString()) &&
                              "供应商不能为空".equals(v.getMessage()));
        assertTrue(hasSupplierIdError);

        // 测试必填字段验证 - 交易类型不能为空
        boolean hasTransactionTypeError = violations.stream()
                .anyMatch(v -> "transactionType".equals(v.getPropertyPath().toString()) &&
                              "交易类型不能为空".equals(v.getMessage()));
        assertTrue(hasTransactionTypeError);

        // 测试必填字段验证 - 商品明细不能为空
        boolean hasItemListError = violations.stream()
                .anyMatch(v -> "itemList".equals(v.getPropertyPath().toString()) &&
                              "商品明细不能为空".equals(v.getMessage()));
        assertTrue(hasItemListError);
    }

    /**
     * 测试Contract7CreateItemDTO的基本属性设置和获取
     * 验证DTO的getter和setter方法是否正常工作
     */
    @Test
    public void testContract7CreateItemDTO() {
        Contract7CreateItemDTO dto = new Contract7CreateItemDTO();
        dto.setProductId(1L);
        dto.setProductName("测试商品");
        dto.setProductUnit("件");
        dto.setProductPrice(new BigDecimal("100.0000"));
        dto.setProductQuantity(new BigDecimal("10.0000"));

        assertNotNull(dto.getProductId());
        assertNotNull(dto.getProductName());
        assertNotNull(dto.getProductUnit());
        assertNotNull(dto.getProductPrice());
        assertNotNull(dto.getProductQuantity());
        assertEquals(1L, dto.getProductId());
        assertEquals("测试商品", dto.getProductName());
        assertEquals("件", dto.getProductUnit());
        assertEquals(new BigDecimal("100.0000"), dto.getProductPrice());
        assertEquals(new BigDecimal("10.0000"), dto.getProductQuantity());
    }

    /**
     * 测试Contract7CreateItemDTO的数据验证功能
     * 验证DTO上的JSR-303注解约束是否正常工作
     */
    @Test
    public void testContract7CreateItemDTOValidation() {
        Contract7CreateItemDTO dto = new Contract7CreateItemDTO();

        // 验证空对象，应该存在违反约束的情况
        Set<ConstraintViolation<Contract7CreateItemDTO>> violations = validator.validate(dto);
        assertFalse(violations.isEmpty());

        // 测试必填字段验证 - 商品不能为空
        boolean hasProductIdError = violations.stream()
                .anyMatch(v -> "productId".equals(v.getPropertyPath().toString()) &&
                              "商品不能为空".equals(v.getMessage()));
        assertTrue(hasProductIdError);

        // 测试必填字段验证 - 商品名称不能为空
        boolean hasProductNameError = violations.stream()
                .anyMatch(v -> "productName".equals(v.getPropertyPath().toString()) &&
                              "商品名称不能为空".equals(v.getMessage()));
        assertTrue(hasProductNameError);

        // 测试必填字段验证 - 商品单位不能为空
        boolean hasProductUnitError = violations.stream()
                .anyMatch(v -> "productUnit".equals(v.getPropertyPath().toString()) &&
                              "商品单位不能为空".equals(v.getMessage()));
        assertTrue(hasProductUnitError);

        // 测试必填字段验证 - 商品单价不能为空
        boolean hasProductPriceError = violations.stream()
                .anyMatch(v -> "productPrice".equals(v.getPropertyPath().toString()) &&
                              "商品单价不能为空".equals(v.getMessage()));
        assertTrue(hasProductPriceError);

        // 测试必填字段验证 - 商品数量不能为空
        boolean hasProductQuantityError = violations.stream()
                .anyMatch(v -> "productQuantity".equals(v.getPropertyPath().toString()) &&
                              "商品数量不能为空".equals(v.getMessage()));
        assertTrue(hasProductQuantityError);
    }

    /**
     * 测试Contract7CreateItemDTO的价格和数量最小值验证
     * 验证DTO上的JSR-303注解约束（如@Min）是否正常工作
     */
    @Test
    public void testContract7CreateItemDTOValidation_PriceAndQuantity() {
        Contract7CreateItemDTO dto = new Contract7CreateItemDTO();
        dto.setProductId(1L);
        dto.setProductName("测试商品");
        dto.setProductUnit("件");
        dto.setProductPrice(new BigDecimal("0")); // 价格必须大于0
        dto.setProductQuantity(new BigDecimal("0")); // 数量必须大于0

        // 验证对象，应该存在违反约束的情况
        Set<ConstraintViolation<Contract7CreateItemDTO>> violations = validator.validate(dto);
        assertFalse(violations.isEmpty());

        // 测试价格最小值验证 - 商品单价必须大于0
        boolean hasPriceMinError = violations.stream()
                .anyMatch(v -> "productPrice".equals(v.getPropertyPath().toString()) &&
                              "商品单价必须大于0".equals(v.getMessage()));
        assertTrue(hasPriceMinError);

        // 测试数量最小值验证 - 商品数量必须大于0
        boolean hasQuantityMinError = violations.stream()
                .anyMatch(v -> "productQuantity".equals(v.getPropertyPath().toString()) &&
                              "商品数量必须大于0".equals(v.getMessage()));
        assertTrue(hasQuantityMinError);
    }

    /**
     * 测试Contract7DetailDTO的基本属性设置和获取
     * 验证DTO的getter和setter方法是否正常工作
     */
    @Test
    public void testContract7DetailDTO() {
        Contract7DetailDTO dto = new Contract7DetailDTO();
        dto.setContractId(1L);
        dto.setContractNumber("HT2025001");
        dto.setContractName("测试合同");
        dto.setStatus(10);

        assertNotNull(dto.getContractId());
        assertNotNull(dto.getContractNumber());
        assertNotNull(dto.getContractName());
        assertNotNull(dto.getStatus());
        assertEquals(1L, dto.getContractId());
        assertEquals("HT2025001", dto.getContractNumber());
        assertEquals("测试合同", dto.getContractName());
        assertEquals(Integer.valueOf(10), dto.getStatus());
    }

    /**
     * 测试Contract7ListVO的基本属性设置和获取
     * 验证VO的getter和setter方法是否正常工作
     */
    @Test
    public void testContract7ListVO() {
        Contract7ListVO dto = new Contract7ListVO();
        dto.setContractId(1L);
        dto.setContractNumber("HT2025001");
        dto.setContractName("测试合同");
        dto.setStatus(10);
        dto.setTotalAmount(new BigDecimal("1000.00"));

        assertNotNull(dto.getContractId());
        assertNotNull(dto.getContractNumber());
        assertNotNull(dto.getContractName());
        assertNotNull(dto.getStatus());
        assertNotNull(dto.getTotalAmount());
        assertEquals(1L, dto.getContractId());
        assertEquals("HT2025001", dto.getContractNumber());
        assertEquals("测试合同", dto.getContractName());
        assertEquals(Integer.valueOf(10), dto.getStatus());
        assertEquals(new BigDecimal("1000.00"), dto.getTotalAmount());
    }

    /**
     * 测试Contract7QueryDTO的基本属性设置和获取
     * 验证DTO的getter和setter方法是否正常工作
     */
    @Test
    public void testContract7QueryDTO() {
        Contract7QueryDTO dto = new Contract7QueryDTO();
        dto.setKeyword("测试");
        dto.setSupplierId(1);
        dto.setStatus(10);

        assertNotNull(dto.getKeyword());
        assertNotNull(dto.getSupplierId());
        assertNotNull(dto.getStatus());
        assertEquals("测试", dto.getKeyword());
        assertEquals(Integer.valueOf(1), dto.getSupplierId());
        assertEquals(Integer.valueOf(10), dto.getStatus());
    }

    /**
     * 测试DTO的JSON序列化和反序列化功能
     * 验证DTO能否正确地转换为JSON字符串以及从JSON字符串还原
     */
    @Test
    public void testJsonSerialization() throws Exception {
        Contract7CreateDTO dto = new Contract7CreateDTO();
        dto.setContractNumber("HT2025001");
        dto.setContractName("测试合同");
        dto.setSupplierId(1);
        dto.setTransactionType("采购");
        dto.setEffectiveDate(new Date());

        // 测试序列化 - 将DTO对象转换为JSON字符串
        String json = objectMapper.writeValueAsString(dto);
        assertNotNull(json);
        assertTrue(json.contains("HT2025001"));

        // 测试反序列化 - 将JSON字符串转换回DTO对象
        Contract7CreateDTO deserialized = objectMapper.readValue(json, Contract7CreateDTO.class);
        assertEquals(dto.getContractNumber(), deserialized.getContractNumber());
        assertEquals(dto.getContractName(), deserialized.getContractName());
    }

    /**
     * 测试Contract7CreateDTO中的商品明细列表属性
     * 验证DTO中嵌套对象列表的设置和获取功能
     */
    @Test
    public void testItemListInContract7CreateDTO() {
        Contract7CreateDTO dto = new Contract7CreateDTO();
        dto.setContractNumber("HT2025001");
        dto.setContractName("测试合同");
        dto.setSupplierId(1);
        dto.setTransactionType("采购");

        // 创建商品明细项
        Contract7CreateItemDTO item = new Contract7CreateItemDTO();
        item.setProductId(1L);
        item.setProductName("测试商品");
        item.setProductUnit("件");
        item.setProductPrice(new BigDecimal("100.0000"));
        item.setProductQuantity(new BigDecimal("10.0000"));

        // 将商品明细项添加到列表中
        ArrayList<Contract7CreateItemDTO> items = new ArrayList<>();
        items.add(item);
        dto.setItemList(items);

        assertNotNull(dto.getItemList());
        assertEquals(1, dto.getItemList().size());
        assertEquals(1L, dto.getItemList().get(0).getProductId());
    }
}
